package cn.stylefeng.guns.modular.baijia;

import cn.stylefeng.guns.config.BaijiaConfig;
import cn.stylefeng.guns.modular.account.model.params.AccountParam;
import cn.stylefeng.guns.modular.account.model.result.AccountResult;
import cn.stylefeng.guns.modular.account.service.AccountService;
import cn.stylefeng.guns.modular.course.model.params.CourseParam;
import cn.stylefeng.guns.modular.course.service.CourseService;
import cn.stylefeng.guns.modular.deduct.model.params.DeductParam;
import cn.stylefeng.guns.modular.deduct.service.DeductService;
import cn.stylefeng.guns.modular.price.model.result.PriceResult;
import cn.stylefeng.guns.modular.price.service.PriceService;
import cn.stylefeng.guns.modular.statistic.entity.DayStatistic;
import cn.stylefeng.guns.modular.statistic.entity.MonthStatistic;
import cn.stylefeng.guns.modular.statistic.model.result.DayStatisticResult;
import cn.stylefeng.guns.modular.statistic.model.result.MonthStatisticResult;
import cn.stylefeng.guns.modular.statistic.service.DayStatisticService;
import cn.stylefeng.guns.modular.statistic.service.MonthStatisticService;
import cn.stylefeng.roses.core.util.MD5Util;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;

/**
 * @Description: BaijiaScheduleTask
 * @Author liuqiang
 * @Date 2020-02-12 14:47
 */
@Service
@Slf4j
public class BaijiaScheduleTask {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DeductService deductService;

    @Autowired
    private AccountService accountService;

    @Autowired
    private CourseService courseService;

    @Autowired
    private PriceService priceService;

    @Autowired
    private DayStatisticService dayStatisticService;

    @Autowired
    private MonthStatisticService monthStatisticService;

    /** 当定时任务失败时，需要手动触发
     * @param dateStr
     */
    public void getSubAccountList(String dateStr){
        List<BaijiaAccount> accountList = subAccountList(new ArrayList<>(), 1);
        log.info("总共获取到{}个子账号",accountList.size());

        //每天统计
        int day = Integer.parseInt(dateStr.replaceAll("-", ""));
        DayStatisticResult dayResult = dayStatisticService.findByDay(day);
        if(dayResult == null){
            DayStatistic param = new DayStatistic();
            param.setCount(accountList.size());
            param.setDay(day);

            dayStatisticService.save(param);
        }else{
            DayStatistic dayStatistic = new DayStatistic();
            dayStatistic.setId(dayResult.getId());
            dayStatistic.setCount(accountList.size());
            dayStatistic.setDay(day);

            dayStatisticService.updateById(dayStatistic);
        }

        //月统计
        int month = Integer.parseInt(dateStr.replaceAll("-", "").substring(0,6));
        MonthStatisticResult monthResult = monthStatisticService.findByMonth(month);
        if(monthResult == null){
            MonthStatistic monthStatistic = new MonthStatistic();
            monthStatistic.setCount(accountList.size());
            monthStatistic.setMonth(month);

            monthStatisticService.save(monthStatistic);
        }else {
            MonthStatistic monthStatistic = new MonthStatistic();
            monthStatistic.setId(monthResult.getId());
            monthStatistic.setMonth(month);
            monthStatistic.setCount(monthResult.getCount() + accountList.size());

            monthStatisticService.updateById(monthStatistic);
        }

        //
        for(BaijiaAccount baijiaAccount : accountList){
            boolean isNew = false;
            AccountResult account = accountService.getByPhone(baijiaAccount.getMobile());
            //没有账号，新增一个
            if(account == null){
                AccountParam accountParam = new AccountParam();
                accountParam.setPhone(baijiaAccount.getMobile());
                accountParam.setSchoolName(baijiaAccount.getCompany());
                accountParam.setSchoolId(baijiaAccount.getPartner_id());
                accountService.add(accountParam);
                log.info("该账户没有注册，新注册账号。phone={},schoolName={},partnerId={}",baijiaAccount.getMobile(),baijiaAccount.getCompany(),baijiaAccount.getPartner_id());
                isNew = true;
            }

            //如果没有schoolId,更新
            if(account.getSchoolId()==null){
                AccountParam accountParam = new AccountParam();
                accountParam.setSchoolId(baijiaAccount.getPartner_id());
                accountParam.setId(account.getId());

                accountService.update(accountParam);
            }

            roomList(baijiaAccount,1,false,dateStr);
            roomList(baijiaAccount,1,false,dateStr);

            if(!isNew){
                AccountResult accountA = accountService.getByPhone(baijiaAccount.getMobile());
                //账户余额不足时，暂时禁用账户
                if(accountA.getBalance().compareTo(new BigDecimal(0))<=0){
                    stopSubAccount(baijiaAccount.getPartner_id());
                    log.info("禁用账号：account={},balance={}",account.getPhone(),accountA.getBalance());
                }
            }
        }
    }

    /**
     * 定时任务
     */
    public void autoSubAccountList(){
        List<BaijiaAccount> accountList = subAccountList(new ArrayList<>(), 1);
        log.info("总共获取到{}个子账号",accountList.size());

        LocalDate localDate = LocalDate.now();
        //每天统计
        int day = Integer.parseInt(localDate.toString().replaceAll("-", ""));
        DayStatisticResult dayResult = dayStatisticService.findByDay(day);
        if(dayResult == null){
            DayStatistic param = new DayStatistic();
            param.setCount(accountList.size());
            param.setDay(day);

            dayStatisticService.save(param);
        }else{
            DayStatistic dayStatistic = new DayStatistic();
            dayStatistic.setId(dayResult.getId());
            dayStatistic.setCount(accountList.size());
            dayStatistic.setDay(day);

            dayStatisticService.updateById(dayStatistic);
        }

        //月统计
        int month = Integer.parseInt(localDate.toString().replaceAll("-", "").substring(0,6));
        MonthStatisticResult monthResult = monthStatisticService.findByMonth(month);
        if(monthResult == null){
            MonthStatistic monthStatistic = new MonthStatistic();
            monthStatistic.setCount(accountList.size());
            monthStatistic.setMonth(month);

            monthStatisticService.save(monthStatistic);
        }else {
            MonthStatistic monthStatistic = new MonthStatistic();
            monthStatistic.setId(monthResult.getId());
            monthStatistic.setMonth(month);
            monthStatistic.setCount(monthResult.getCount() + accountList.size());

            monthStatisticService.updateById(monthStatistic);
        }


        for(BaijiaAccount baijiaAccount : accountList){
            boolean isNew = false;
            AccountResult account = accountService.getByPhone(baijiaAccount.getMobile());
            //没有账号，新增一个
            if(account == null){
                AccountParam accountParam = new AccountParam();
                accountParam.setPhone(baijiaAccount.getMobile());
                accountParam.setSchoolName(baijiaAccount.getCompany());
                accountParam.setSchoolId(baijiaAccount.getPartner_id());
                accountService.add(accountParam);
                log.info("该账户没有注册，新注册账号。phone={},schoolName={},partnerId={}",baijiaAccount.getMobile(),baijiaAccount.getCompany(),baijiaAccount.getPartner_id());
                isNew = true;
            }

            //如果没有schoolId,更新
            if(account.getSchoolId()==null){
                AccountParam accountParam = new AccountParam();
                accountParam.setSchoolId(baijiaAccount.getPartner_id());
                accountParam.setId(account.getId());

                accountService.update(accountParam);
            }

            roomList(baijiaAccount,1,true,null);
            roomList(baijiaAccount,1,true,null);

            if(!isNew){
                AccountResult accountA = accountService.getByPhone(baijiaAccount.getMobile());
                //账户余额不足时，暂时禁用账户
                if(accountA.getBalance().compareTo(new BigDecimal(0))<=0){
                    stopSubAccount(baijiaAccount.getPartner_id());
                    log.info("禁用账号：account={},balance={}",account.getPhone(),accountA.getBalance());
                }
            }
        }
    }

    /**
     *  停用子账号
     * @param partnerId
     */
    private void stopSubAccount(Integer partnerId) {
        Map<String,Object> map = new TreeMap();
        map.put("partner_id", BaijiaConfig.PARTNER_ID);
        map.put("sub_partner_id", partnerId);
        map.put("timestamp", System.currentTimeMillis()/1000L);
        map.put("sign",getSign(map));

        UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(BaijiaConfig.STOP_SUB_ACCOUNT_URL)
                .queryParam("partner_id", map.get("partner_id"))
                .queryParam("sub_partner_id", map.get("sub_partner_id"))
                .queryParam("timestamp", map.get("timestamp"))
                .queryParam("sign", map.get("sign"))
                .build();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String,String>> requestEntity = new HttpEntity(uriComponents.getQueryParams(),headers);

        ResponseEntity<String> responseEntity = restTemplate.postForEntity(uriComponents.toUri(), requestEntity, String.class);
        JSONObject body = JSONObject.parseObject(responseEntity.getBody());
        JSONObject data = body.getJSONObject("data");
        int partner_id = data.getIntValue("partner_id");
        if(partner_id != partnerId){
            log.error("停用子账号失败：{}",partnerId);
        }
    }

    /**
     *  获取房间列表
     * @param baijiaAccount
     * @param page
     * @param
     */
    private void roomList(BaijiaAccount baijiaAccount,int page,boolean auto,String dateStr) {
        Map<String,Object> map = new TreeMap();
        map.put("partner_id", baijiaAccount.getPartner_id());
        map.put("timestamp", System.currentTimeMillis()/1000L);
        map.put("page", 1);
        map.put("limit", 100);
//        map.put("product_type", type);
        map.put("sign",getSign(map,baijiaAccount.getPartner_key()));

        UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(String.format(BaijiaConfig.ROOM_LIST,baijiaAccount.getPrivate_domain()))
                .queryParam("partner_id", map.get("partner_id"))
//                .queryParam("product_type", map.get("product_type"))
                .queryParam("timestamp", map.get("timestamp"))
                .queryParam("page", map.get("page"))
                .queryParam("limit", map.get("limit"))
                .queryParam("sign", map.get("sign"))
                .build();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String,String>> requestEntity = new HttpEntity(uriComponents.getQueryParams(),headers);

        ResponseEntity<String> responseEntity = restTemplate.postForEntity(uriComponents.toUri(), requestEntity, String.class);
        JSONObject body = JSONObject.parseObject(responseEntity.getBody());
        JSONObject data = body.getJSONObject("data");

        int total = data.getIntValue("total");
        JSONArray list = data.getJSONArray("list");
        log.info("账号={} 获取到 room个数={}",baijiaAccount.getPartner_id(),list.size());
        for(int i = 0;i < list.size(); i ++){
            BaijiaRoom room = list.getObject(i, BaijiaRoom.class);
            liveReport(room,baijiaAccount,auto,dateStr);
        }

        if(total > 100){
            int totalPage = total/100;
            if(page < totalPage){
                roomList(baijiaAccount,page+1,auto,dateStr);
            }
        }
    }

    /** 获取房间直播记录
     * @param room
     * @param account
     */
    public void liveReport(BaijiaRoom room,BaijiaAccount account,boolean auto,String dateStr){

        //老师扣费
        BaijiaLiveReport teacher = getLiveReport(room, account, auto, dateStr, "teacher");
        if(teacher != null){
            deductBalance(room,account,teacher,1);
        }

        //助教扣费
        BaijiaLiveReport admin = getLiveReport(room, account, auto, dateStr, "admin");
        if(admin != null){
            deductBalance(room,account,admin,2);
        }

        Map<String,Object> map = new TreeMap();
        map.put("partner_id", account.getPartner_id());
        map.put("room_id", room.getRoom_id());
        if(auto){
            map.put("date",LocalDate.now().toString());
        }else {
            map.put("date",dateStr);
        }
        map.put("timestamp", System.currentTimeMillis()/1000L);
        map.put("page", 1);
        map.put("page_size", 100);
        map.put("sign",getSign(map,account.getPartner_key()));

        UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(String.format(BaijiaConfig.LIVE_REPORT,account.getPrivate_domain()))
                .queryParam("partner_id", map.get("partner_id"))
                .queryParam("room_id", map.get("room_id"))
                .queryParam("date", map.get("date"))
                .queryParam("timestamp", map.get("timestamp"))
                .queryParam("page", map.get("page"))
                .queryParam("page_size", map.get("page_size"))
                .queryParam("sign", map.get("sign"))
                .build();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String,String>> requestEntity = new HttpEntity(uriComponents.getQueryParams(),headers);

        ResponseEntity<String> responseEntity = restTemplate.postForEntity(uriComponents.toUri(), requestEntity, String.class);
        JSONObject body = JSONObject.parseObject(responseEntity.getBody());
        JSONObject data = body.getJSONObject("data");

        JSONArray list = data.getJSONArray("room_user_info");
        log.info("account={}, room={},获取到的直播对象数={}",account.getPartner_id(),room.getRoom_id(),list.size());
        for(int i = 0;i < list.size();i ++){
            BaijiaLiveReport liveReport = list.getObject(i, BaijiaLiveReport.class);
            //学生扣费
            deductBalance(room, account, liveReport,0);

            //上课记录
            CourseParam course = new CourseParam();
            course.setCourseName(room.getTitle());
            course.setStudentName(liveReport.getUser_name());
            course.setTeacherName(teacher.getUser_name());
            course.setStudentId(liveReport.getUser_number());
            course.setPhone(account.getMobile());
            course.setCourseId(room.getRoom_id());

            course.setStartTime(new Date(room.getStart_time()*1000L));
            course.setEndTime(new Date(room.getEnd_time()*1000L));
            log.info("endTime={},startTime={}",room.getStart_time(),room.getEnd_time());
            int minute = (room.getEnd_time() - room.getStart_time()) / 60;
            course.setDuration(minute);
            course.setConsumeDuration(liveReport.getActual_listen_time()/60);

            courseService.add(course);

        }
    }

    private void deductBalance(BaijiaRoom room, BaijiaAccount account, BaijiaLiveReport liveReport,int userType) {
        //生成扣费记录
        DeductParam deduct = new DeductParam();
        deduct.setCourseName(room.getTitle());
        deduct.setCourseType(String.valueOf(room.getType()));
        int duration = liveReport.getActual_listen_time() / 60;
        deduct.setDuration(duration);
        deduct.setUserName(liveReport.getUser_name());
        deduct.setUserId(liveReport.getUser_number());
        deduct.setUserType(userType);
        deduct.setPhone(account.getMobile());
        deduct.setCourseId(room.getRoom_id());

        PriceResult price = priceService.findByType(room.getType());

        deduct.setPrice(price.getPrice());
        BigDecimal totalPrice = price.getPrice().divide(new BigDecimal(price.getMinutes())).multiply(new BigDecimal(duration));
        deduct.setTotalPrice(totalPrice);

        log.info("username:{}", liveReport.getUser_name());
        log.info("account={},room={},userId={},totalPrice={}",account.getPartner_id(),room.getRoom_id(),liveReport.getUser_name(),totalPrice);
        //从学校账号扣钱,更新上课次数,更新最后上时间,累计消费金额
        BigDecimal bigDecimal = accountService.updateByPhone(account.getMobile(), totalPrice, room.getStart_time());
        deduct.setBalance(bigDecimal);

        deductService.add(deduct);
    }

    /** 获取老师,助教
     * @param room
     * @param account
     * @return
     */
    private BaijiaLiveReport getLiveReport(BaijiaRoom room,BaijiaAccount account,boolean auto,String dateStr,String userType){
        Map<String,Object> map = new TreeMap();
        map.put("partner_id", account.getPartner_id());
        map.put("room_id", room.getRoom_id());
        map.put("type",userType);
        if(auto){
            map.put("date",LocalDate.now().toString());
        }else {
            map.put("date",dateStr);
        }
        map.put("timestamp", System.currentTimeMillis()/1000L);
        map.put("page", 1);
        map.put("page_size", 1);
        map.put("sign",getSign(map,account.getPartner_key()));

        UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(String.format(BaijiaConfig.LIVE_REPORT,account.getPrivate_domain()))
                .queryParam("partner_id", map.get("partner_id"))
                .queryParam("room_id", map.get("room_id"))
                .queryParam("type", map.get("type"))
                .queryParam("date", map.get("date"))
                .queryParam("timestamp", map.get("timestamp"))
                .queryParam("page", map.get("page"))
                .queryParam("page_size", map.get("page_size"))
                .queryParam("sign", map.get("sign"))
                .build();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String,String>> requestEntity = new HttpEntity<>(uriComponents.getQueryParams(),headers);

        ResponseEntity<String> responseEntity = restTemplate.postForEntity(uriComponents.toUri(), requestEntity, String.class);
        JSONObject body = JSONObject.parseObject(responseEntity.getBody());
        JSONObject data = body.getJSONObject("data");

        JSONArray list = data.getJSONArray("room_user_info");
        if(list.size() == 0){
            return null;
        }
        BaijiaLiveReport liveReport = list.getObject(0, BaijiaLiveReport.class);
        return liveReport;
    }

    /** 获取子账号列表
     * @param subAccountList
     * @param page
     * @return
     */
    private List<BaijiaAccount> subAccountList(List<BaijiaAccount> subAccountList, int page) {

        SortedMap<String, Object> map = new TreeMap<>();
        map.put("partner_id", BaijiaConfig.PARTNER_ID);
        map.put("status", 1);
        map.put("timestamp", System.currentTimeMillis()/1000L);
        map.put("page", page);
        map.put("page_size", 100);
        map.put("sign",getSign(map));

        UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(String.format(BaijiaConfig.SUB_ACCOUNT_URL,BaijiaConfig.PRIVATE_DOMIN))
                .queryParam("partner_id", map.get("partner_id"))
                .queryParam("status", map.get("status"))
                .queryParam("timestamp", map.get("timestamp"))
                .queryParam("page", map.get("page"))
                .queryParam("page_size", map.get("page_size"))
                .queryParam("sign", map.get("sign"))
                .build();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(uriComponents.getQueryParams(),headers);

        ResponseEntity<String> responseEntity = restTemplate.postForEntity(uriComponents.toUri(), requestEntity, String.class);
        JSONObject body = JSONObject.parseObject(responseEntity.getBody());
        JSONObject data = body.getJSONObject("data");
        int total = data.getIntValue("total");

        JSONArray list = data.getJSONArray("list");
        for(int i = 0;i < list.size();i ++){
            BaijiaAccount baijiaAccount = list.getObject(i, BaijiaAccount.class);

            getSubAccountInfo(baijiaAccount);
            subAccountList.add(baijiaAccount);
        }

        if(total > 100){
            int totalPage = total/100;
            if(page < totalPage){
                subAccountList(subAccountList,page+1);
            }
        }

        return subAccountList;
    }

    /** 获取子账号信息
     * @param baijiaAccount
     */
    private void getSubAccountInfo(BaijiaAccount baijiaAccount) {
        SortedMap<String, Object> map = new TreeMap<>();
        map.put("partner_id", BaijiaConfig.PARTNER_ID);
        map.put("sub_partner_id", baijiaAccount.getPartner_id());
        map.put("timestamp", System.currentTimeMillis()/1000L);
        map.put("sign",getSign(map));

        UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(BaijiaConfig.SUB_ACCOUNT_INFO_URL)
                .queryParam("partner_id", map.get("partner_id"))
                .queryParam("sub_partner_id", map.get("sub_partner_id"))
                .queryParam("timestamp", map.get("timestamp"))
                .queryParam("sign", map.get("sign"))
                .build();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(uriComponents.getQueryParams(),headers);

        ResponseEntity<String> responseEntity = restTemplate.postForEntity(uriComponents.toUri(), requestEntity, String.class);
        JSONObject body = JSONObject.parseObject(responseEntity.getBody());
        JSONObject data = body.getJSONObject("data");

        String partnerKey = data.getString("partner_key");
        baijiaAccount.setPartner_key(partnerKey);
    }

    public String getSign(Map<String, Object> map){
        StringBuilder sb = new StringBuilder();
        map.forEach((k,v)->{
            sb.append(k).append("=").append(v).append("&");
        });

        sb.append("partner_key=").append(BaijiaConfig.PARTNER_KEY);

        return MD5Util.encrypt(sb.toString());
    }

    public String getSign(Map<String, Object> map,String partnerKey){
        StringBuilder sb = new StringBuilder();
        map.forEach((k,v)->{
            sb.append(k).append("=").append(v).append("&");
        });

        sb.append("partner_key=").append(partnerKey);

        return MD5Util.encrypt(sb.toString());
    }

    public int getCurrentDay(){
        return Integer.parseInt(LocalDate.now().toString().replace("-",""));
    }

    public int getCurrentMonth(){
        return Integer.parseInt(LocalDate.now().toString().replace("-","").substring(0,6));
    }

}
